<template>
  <div>
    <a-drawer
      :title="title"
      placement="right"
      width="90%"
      :closable="true"
      :visible="visible"
      @close="onClose"
      :bodyStyle="{padding: 0}"
    >
      <a-form-model
        ref="addBizModel"
        :model="bizModelData"
        :label-col="labelCol"
        :wrapper-col="wrapperCol"
        style="margin-top: 50px;"
      >
        <a-form-model-item ref="modelName" label="业务数据模型名称">
          <a-input v-model="bizModelData.modelName"/>
        </a-form-model-item>
        <a-form-model-item label="数据访问权限">
          <a-radio-group v-model="authClass" style="width: 100%">
            <a-form-model-item>
              <a-radio value="1">普通配权（登陆用户属于或等于...)</a-radio>
            </a-form-model-item>
            <div style="margin-left: 40px">
              <a-form-model-item>
                <a-checkbox-group v-if="authClass==='1'" v-model="bizModelData.authType" :options="authTypeList"
                                  @change="authTypeOnChange"></a-checkbox-group>
              </a-form-model-item>
              <a-form-model-item v-if="bizModelData.authType.indexOf('R') + bizModelData.authType.indexOf('A') > -2  && authClass==='1'">
                <label>选择角色：</label>
                <a-select mode="multiple" :allowClear="true" v-model="bizModelData.authRoles">
                  <a-select-option v-for="r in allRoles" :key="r.roleName">{{r.roleName}}</a-select-option>
                </a-select>
              </a-form-model-item>
              <a-form-model-item v-if="bizModelData.authType.indexOf('D') + bizModelData.authType.indexOf('A') > -2 && authClass==='1'">
                <label>选择部门：</label>
                <a-tree-select
                  :allowClear="true"
                  multiple
                  :treeData="allDepts"
                  v-model="bizModelData.authDepts">
                </a-tree-select>
              </a-form-model-item>
              <a-form-model-item v-if="bizModelData.authType.indexOf('F') > -1 && authClass==='1'">
                <label>字段名：</label>
                <a-input v-model="bizModelData.authFixedField"/>
              </a-form-model-item>
            </div>
            <a-form-model-item>
              <a-radio value="2">插件判断（参数为登陆用户）</a-radio>
            </a-form-model-item>
            <a-form-model-item v-if="authClass==='2'" style="margin-left: 40px">
              <label>插件路径：</label>
              <a-input v-model="bizModelData.authPluginPath"/>
            </a-form-model-item>
          </a-radio-group>
        </a-form-model-item>
        <a-form-model-item label="字段配置" style="width: 100%">
          <a-button-group>
          <a-button class="editable-add-btn" @click="handleAddField">添加字段</a-button>
          <a-button class="editable-add-btn" @click="handleDelField">删除字段</a-button>
          </a-button-group>
          <!--模型字段配置表-->
          <a-table
            :row-selection="{selectedRowKeys: selectedFieldRows, onChange: fieldMultiSelectedOnChange}"
            :columns="fieldCols" :data-source="fieldData" :pagination="false">
            <template
              v-for="col in ['fieldName', 'fatherFieldName', 'fieldDesc', 'isPriKey', 'isIndex', 'isDict', 'fieldType']"
              :slot="col"
              slot-scope="text, record, index"
            >
              <div :key="col">
                <a-input
                  v-if="record.editable && ['fieldName', 'fatherFieldName', 'fieldDesc'].indexOf(col) > -1"
                  style="margin: -5px 0"
                  :value="text"
                  @change="e => handleFieldChange(e.target.value, record.key, col)"
                />
                <a-select
                  v-else-if="record.editable && col==='fieldType'"
                  v-model="text"
                  @change="e => handleFieldChange(e, record.key, col)"
                >
                  <a-select-option v-for="item in fieldTypeList" :key="item.value">
                    {{item.label}}
                  </a-select-option>
                </a-select>
                <a-switch v-else-if="record.editable && ['isPriKey', 'isIndex', 'isDict'].indexOf(col) > -1"
                          :checked="text"
                          @change="e => handleFieldChange(e, record.key, col)">
                </a-switch>
                <div v-else-if="!record.editable && ['isPriKey', 'isIndex', 'isDict'].indexOf(col) > -1">
                  <div v-if="text===true"><a-tag color="green">是</a-tag></div>
                  <div v-else-if="text===false">否</div>
                </div>
                <div v-else-if="!record.editable && col==='fieldName' && record['fatherFieldName']!==null && record['fatherFieldName']!==''">
                  <a-tag color="#D3D3D3">{{ text }}</a-tag>
                </div>
                <div v-else>{{ text }}</div>
              </div>
            </template>
            <template slot="operation" slot-scope="text, record">
              <div v-if="record.editable">
                <a @click="() => saveField(record.key)">保存</a>
                <a @click="() => cancelField(record.key)">取消</a>
              </div>
              <div v-else>
                <a :disabled="fieldEditingKey !== ''" @click="() => editField(record.key)">编辑</a>
                <a @click="() => delField(record.key)">删除</a>
              </div>
            </template>
            <template slot="operationAlg" slot-scope="text, record">
              <div v-if="record.editable===undefined">
                <a @click="() => showAlgCfg(record.key)">查看</a>
                <a @click="() => AddAlgCfg(record.key)">添加</a>
                <a @click="() => pasteAlgCfg(record.key)">粘贴</a>
              </div>
            </template>
          </a-table>
          <div v-if="displayAlgCfg===true">
            <span>{{currField}}字段的赋值算法：</span>
            <!--单一字段配置表-->
            <a-table :columns="algCols" :data-source="currFieldAlgData" :pagination="false">
              <template
                v-for="col in ['procDefId', 'nodeId', 'priKeyAlgType', 'algType', 'priKeyAlgDesc', 'algDesc']"
                :slot="col"
                slot-scope="text, record, index"
              >
                <div :key="col">
                  <div v-if="record.editable">
                    <a-input
                      v-if="['priKeyAlgDesc', 'algDesc'].indexOf(col) > -1"
                      style="margin: -5px 0"
                      :value="text"
                      @change="e => handleAlgChange(e.target.value, record.key, col)"
                    />
                    <a-select
                      v-else-if="col==='procDefId'"
                      v-model="text"
                      :showArrow="false"
                      :showSearch="true"
                      @change="e => handleProcDefIdFieldChange(e, record.key, col)"
                    >
                      <a-select-option v-for="(value, key) in procDefList" :key="key">
                        {{ value }}
                      </a-select-option>
                    </a-select>
                    <a-select
                      v-else-if="col==='nodeId'"
                      v-model="text"
                      :showArrow="false"
                      :showSearch="true"
                      @change="e => handleAlgChange(e, record.key, col)"
                    >
                      <a-select-option v-for="(value, key) in nodeIdList" :key="key">
                        {{ key }}
                      </a-select-option>
                    </a-select>
                    <a-select
                      v-else-if="col==='priKeyAlgType'"
                      v-model="text"
                      @change="e => handleAlgChange(e, record.key, col)"
                    >
                      <a-select-option v-for="item in priKeyAlgTypeList" :key="item.value">
                        {{item.label}}
                      </a-select-option>
                    </a-select>
                    <a-select
                      v-else-if="col==='algType'"
                      v-model="text"
                      @change="e => handleAlgChange(e, record.key, col)"
                    >
                      <a-select-option v-for="item in algTypeList" :key="item.value">
                        {{item.label}}
                      </a-select-option>
                    </a-select>
                  </div>
                  <div v-else>
                    <template v-if="col==='priKeyAlgType'">{{rendPriKeyAlgType(text)}}</template>
                    <template v-else-if="col==='algType'">{{rendAlgType(text)}}</template>
                    <template v-else-if="col==='procDefId'">{{rendProcDefId(text)}}</template>
                    <template v-else>{{ text }}</template>
                  </div>
                </div>
              </template>
              <template slot="operation" slot-scope="text, record">
                <div v-if="record.editable">
                  <a @click="() => saveAlgCfg(record.key)">保存</a>
                  <a @click="() => cancelAlgCfg(record.key)">取消</a>
                </div>
                <div v-else>
                  <a :disabled="algEditingKey !== ''" @click="() => editAlgCfg(record.key)">编辑</a>
                  <a @click="() => delAlgCfg(record.key)">删除</a>
                  <a @click="() => copyAlgCfg(record.key)">复制</a>
                </div>
              </template>
            </a-table>
          </div>
        </a-form-model-item>
        <a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
          <a-button type="primary" @click="onSubmitAndClose">
            保存并关闭
          </a-button>
          <a-button type="primary" style="margin-left: 10px;" @click="onSubmit">
            保存
          </a-button>
        </a-form-model-item>
      </a-form-model>
    </a-drawer>
  </div>
</template>

<script>
import DeptInputTree from '../dept/DeptInputTree'

export default {
  name: 'AddBizModel',
  components: {DeptInputTree},
  data () {
    return {
      title: '',
      visible: false,
      labelCol: {span: 3},
      wrapperCol: {span: 20},
      allRoles: [],
      allDepts: [],
      authClass: '',
      fieldData: [],
      cacheFieldData: [],
      currField: '',
      currFieldKey: '',
      selectedFieldRows: '',
      currFieldAlgData: [],
      displayAlgCfg: false,
      fieldEditingKey: '',
      algEditingKey: '',
      algClipboard: {},
      procDefList: {},
      nodeIdList: {},
      authTypeTmp: [],
      bizModelData: {
        modelId: -1,
        modelName: '',
        authType: [],
        authParam: '',
        authRoles: [],
        authDepts: [],
        authFixedField: '',
        authPluginPath: ''
      }
    }
  },
  methods: {
    handleAddField () {
      this.checkIsEditing()
      let newData = {
        key: this.fieldData.length,
        fieldName: '',
        fieldDesc: '',
        fieldType: '',
        isPriKey: false,
        isIndex: false,
        isDict: false,
        algCount: 0,
        algData: []
      }
      this.fieldData = [...this.fieldData, newData]
      this.cacheFieldData = this.fieldData.map(item => ({ ...item })) // 刷新cacheData
      this.editField(newData.key)
    },
    handleDelField () {
      for (let i in this.selectedFieldRows) {
        this.delField(this.selectedFieldRows[i])
      }
    },
    handleFieldChange (value, key, column) {
      const newData = [...this.fieldData]
      const target = newData.filter(item => key === item.key)[0]
      if (target) {
        target[column] = value
        this.fieldData = newData
      }
    },
    editField (key) {
      const newData = [...this.fieldData]
      const target = newData.filter(item => key === item.key)[0]
      this.fieldEditingKey = key
      if (target) {
        target.editable = true
        this.displayAlgCfg = false
        this.fieldData = newData
      }
    },
    saveField (key) {
      const newData = [...this.fieldData]
      const newCacheData = [...this.cacheFieldData]
      const target = newData.filter(item => key === item.key)[0]
      const targetCache = newCacheData.filter(item => key === item.key)[0]
      if (target && targetCache) {
        delete target.editable
        this.fieldData = newData
        Object.assign(targetCache, target)
        this.cacheFieldData = newCacheData
      }
      this.fieldEditingKey = ''
    },
    cancelField (key) {
      const newData = [...this.fieldData]
      const target = newData.filter(item => key === item.key)[0]
      this.fieldEditingKey = ''
      if (target) {
        Object.assign(target, this.cacheFieldData.filter(item => key === item.key)[0])
        delete target.editable
        this.fieldData = newData
      }
    },
    delField (key) {
      this.checkIsEditing()
      const newData = [...this.fieldData]
      const newCacheData = [...this.cacheFieldData]
      this.fieldData.splice(newData.findIndex(item => key === item.key), 1)
      this.cacheFieldData.splice(newCacheData.findIndex(item => key === item.key), 1)
    },
    authTypeOnChange () {
      let authType = this.bizModelData.authType
      // 计算勾选的项
      const changeItem = authType.filter(item => this.authTypeTmp.indexOf(item) <= -1)[0]
      // R 或 D 选了的时候不能选 A，反之亦然
      if (changeItem === 'R' && authType.indexOf('A') > -1) {
        authType.splice(authType.indexOf('A'), 1)
      }
      if (changeItem === 'D' && authType.indexOf('A') > -1) {
        authType.splice(authType.indexOf('A'), 1)
      }
      if (changeItem === 'A' && authType.indexOf('R') > -1) {
        authType.splice(authType.indexOf('R'), 1)
      }
      if (changeItem === 'A' && authType.indexOf('D') > -1) {
        authType.splice(authType.indexOf('D'), 1)
      }
      this.authTypeTmp = Array.from(authType)
    },
    show () {
      Object.assign(this.$data, this.$options.data())
      this.visible = true
    },
    onClose () {
      this.visible = false
      Object.assign(this.$data, this.$options.data())
      this.$emit('close')
    },
    onSubmitAndClose () {
      this.checkIsEditing()
      this.$post('/bizModel/add', {
        ...this.bizModelData,
        bizCfgJson: JSON.stringify(this.fieldData)
      }).then(() => {
        this.$message.success('保存成功')
        this.onClose()
      })
    },
    onSubmit () {
      this.checkIsEditing()
      this.$post('/bizModel/add', {
        ...this.bizModelData,
        bizCfgJson: JSON.stringify(this.fieldData)
      }).then(() => {
        this.$message.success('保存成功')
      })
    },
    showAlgCfg (key) {
      this.checkIsEditing()
      this.displayAlgCfg = true
      const fieldData = [...this.fieldData]
      const target = fieldData.filter(item => key === item.key)[0]
      this.currField = target['fieldName']
      this.currFieldAlgData = target.algData.map(item => ({ ...item }))
      this.currFieldKey = key
    },
    handleAlgChange (value, key, column) {
      const newData = [...this.currFieldAlgData]
      const target = newData.filter(item => key === item.key)[0]
      if (target) {
        target[column] = value
        this.currFieldAlgData = newData
      }
    },
    handleProcDefIdFieldChange (value, key, column) {
      this.handleAlgChange(value, key, column)
      // 联动加载NodeIds（触发事件列表）
      this.$get('bizModel/getEvent/' + value).then((r) => {
        this.nodeIdList = r.data
      })
    },
    AddAlgCfg (key) {
      this.showAlgCfg(key)
      const newData = {
        key: this.currFieldAlgData.length,
        procDefId: '',
        nodeId: '',
        algType: '',
        algDesc: ''
      }
      this.currFieldAlgData = [...this.currFieldAlgData, newData]
      const fieldCache = this.fieldData.filter(item => this.currFieldKey === item.key)[0]
      fieldCache.algData = [...fieldCache.algData, newData]
      this.cacheFieldData = this.fieldData.map(item => ({ ...item }))
      this.editAlgCfg(newData.key)
    },
    copyAlgCfg (key) {
      this.checkIsEditing()
      const newData = [...this.currFieldAlgData]
      Object.assign(this.algClipboard, newData.filter(item => key === item.key)[0])
      this.$message.success('算法复制成功')
    },
    pasteAlgCfg (key) {
      this.checkIsEditing()
      if (JSON.stringify(this.algClipboard) !== '{}') {
        this.showAlgCfg(key)
        let newData = {}
        Object.assign(newData, this.algClipboard)
        newData.key = this.currFieldAlgData.length
        this.currFieldAlgData = [...this.currFieldAlgData, newData]
        // 同步到fieldData
        const fieldCache = this.fieldData.filter(item => this.currFieldKey === item.key)[0]
        fieldCache.algData = [...fieldCache.algData, newData]
        fieldCache.algCount = this.currFieldAlgData.length
        this.cacheFieldData = this.fieldData.map(item => ({ ...item }))
      } else {
        this.$message.info('粘贴板上无可用的算法')
      }
    },
    delAlgCfg (key) {
      this.checkIsEditing()
      const newData = [...this.currFieldAlgData]
      const newCacheData = [...this.fieldData]
      const fieldCache = newCacheData.filter(item => this.currFieldKey === item.key)[0]
      this.currFieldAlgData.splice(newData.findIndex(item => key === item.key), 1)
      fieldCache.algData.splice(fieldCache.algData.findIndex(item => key === item.key), 1)
      this.cacheFieldData = this.fieldData.map(item => ({ ...item }))
    },
    editAlgCfg (key) {
      const newData = [...this.currFieldAlgData]
      const target = newData.filter(item => key === item.key)[0]
      this.algEditingKey = key
      if (target) {
        target.editable = true
        this.currFieldAlgData = newData
      }
    },
    saveAlgCfg (key) {
      const newData = [...this.currFieldAlgData]
      const newCacheData = [...this.fieldData]
      const target = newData.filter(item => key === item.key)[0]
      const fieldCache = newCacheData.filter(item => this.currFieldKey === item.key)[0]
      const targetCache = fieldCache.algData.filter(item => key === item.key)[0]
      if (target && targetCache) {
        delete target.editable
        this.currFieldAlgData = newData
        Object.assign(targetCache, target)
        fieldCache.algCount = this.currFieldAlgData.length
        this.fieldData = newCacheData
        this.cacheFieldData = this.fieldData.map(item => ({ ...item }))
      }
      this.algEditingKey = ''
    },
    cancelAlgCfg (key) {
      const newData = [...this.currFieldAlgData]
      const target = newData.filter(item => key === item.key)[0]
      this.algEditingKey = ''
      if (target) {
        const fieldCache = this.fieldData.filter(item => this.currFieldKey === item.key)[0]
        const targetCache = fieldCache.algData.filter(item => key === item.key)[0]
        Object.assign(target, targetCache)
        delete target.editable
        this.currFieldAlgData = newData
      }
    },
    setEditData (modelData, fieldData) {
      this.title = '编辑业务数据模型'
      this.bizModelData.modelId = modelData.modelId
      this.bizModelData.modelName = modelData.modelName
      this.bizModelData.authType = modelData.authType.split(',') // 因存在类型转换问题，故按字段复制modelData
      this.bizModelData.authParam = modelData.authParam
      this.bizModelData.authRoles = modelData.authRoles.split(',')
      this.bizModelData.authDepts = modelData.authDepts.split(',')
      this.bizModelData.authFixedField = modelData.authFixedField
      this.bizModelData.authPluginPath = modelData.authPluginPath
      this.fieldData = fieldData
      this.cacheFieldData = this.fieldData.map(item => ({ ...item }))
      if (this.bizModelData.authType !== []) {
        this.authClass = '1'
      } else if (this.bizModelData.authPluginPath !== '') {
        this.authClass = '2'
      }
    },
    checkIsEditing () {
      this.selectedFieldRows = []
      if (this.fieldEditingKey !== '') {
        this.saveField(this.fieldEditingKey)
      }
      if (this.algEditingKey !== '') {
        this.saveAlgCfg(this.algEditingKey)
      }
    },
    rendPriKeyAlgType (value) {
      const rs = this.priKeyAlgTypeList.filter(item => value === item.value)[0]
      if (rs) { return rs.label } else { return value }
    },
    rendAlgType (value) {
      const rs = this.algTypeList.filter(item => value === item.value)[0]
      if (rs) { return rs.label } else { return value }
    },
    rendProcDefId (value) {
      for (let key in this.procDefList) {
        if (key === value) {
          return this.procDefList[key]
        }
      }
    },
    fieldMultiSelectedOnChange (selectedRowKeys, selectedRows) {
      this.selectedFieldRows = selectedRowKeys
    }
  },
  watch: {
    visible: function () {
      if (this.visible === true) {
        this.$get('role/getAll').then((r) => {
          this.allRoles = r.data
        })
        this.$get('dept').then((r) => {
          this.allDepts = r.data.rows.children
        })
        this.$get('bizModel/getProcesses').then((r) => {
          this.procDefList = r.data
        })

        if (this.bizModelData.modelId < 0) {
          this.title = '添加业务数据模型'
        }
      }

      this.selectedFieldRows = []
    }
  },
  computed: {
    authTypeList () {
      return [
        {label: '某角色', value: 'R'},
        {label: '某部门', value: 'D'},
        {label: '同时属于部门和角色', value: 'A'},
        {label: '数据中指定字段值', value: 'F'}
      ]
    },
    priKeyAlgTypeList () {
      return [
        {label: '按模型主键系统生成', value: '1'},
        {label: '取流程数据', value: '2'}
      ]
    },
    fieldTypeList () {
      return [
        {label: 'String', value: 'String'},
        {label: 'Date', value: 'Date'},
        {label: 'Array', value: 'Array'}
      ]
    },
    algTypeList () {
      return [
        {label: '取流程数据', value: '2'},
        {label: '固定值', value: '3'},
        {label: '插件计算', value: '4'}
      ]
    },
    fieldCols () {
      return [
        {title: '操作', dataIndex: 'operation', scopedSlots: {customRender: 'operation'}},
        {title: '算法', dataIndex: 'operationAlg', scopedSlots: {customRender: 'operationAlg'}},
        {title: '字段名', dataIndex: 'fieldName', scopedSlots: { customRender: 'fieldName' }},
        {title: '字段描述', dataIndex: 'fieldDesc', scopedSlots: { customRender: 'fieldDesc' }},
        {title: '字段类型', dataIndex: 'fieldType', scopedSlots: { customRender: 'fieldType' }},
        {title: '父字段名', dataIndex: 'fatherFieldName', scopedSlots: { customRender: 'fatherFieldName' }},
        {title: '是否主键', dataIndex: 'isPriKey', width: 80, scopedSlots: {customRender: 'isPriKey'}},
        {title: '是否建立索引', dataIndex: 'isIndex', width: 80, scopedSlots: {customRender: 'isIndex'}},
        {title: '是否建立数据字典', dataIndex: 'isDict', width: 80, scopedSlots: {customRender: 'isDict'}},
        {title: '已配算法数量', dataIndex: 'algCount', width: 80, scopedSlots: {customRender: 'algCount'}}

      ]
    },
    algCols () {
      return [
        {title: '操作', dataIndex: 'operation', scopedSlots: {customRender: 'operation'}},
        {title: '流程定义', dataIndex: 'procDefId', scopedSlots: {customRender: 'procDefId'}},
        {title: '触发事件', dataIndex: 'nodeId', scopedSlots: {customRender: 'nodeId'}}, // 触发事件即节点ID
        {title: '主键算法', dataIndex: 'priKeyAlgType', scopedSlots: {customRender: 'priKeyAlgType'}},
        {title: '主键算法表达', dataIndex: 'priKeyAlgDesc', scopedSlots: {customRender: 'priKeyAlgDesc'}},
        {title: '值算法', dataIndex: 'algType', scopedSlots: {customRender: 'algType'}},
        {title: '值算法表达', dataIndex: 'algDesc', scopedSlots: {customRender: 'algDesc'}}
      ]
    }
  }
}
</script>

<style scoped>
  .editable-row-operations a {
    margin-right: 8px;
  }
</style>
